package com.ecommerce.auth.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import javax.crypto.SecretKey;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

@Component
public class JwtUtil {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private Long expiration;

    @Value("${jwt.refresh-expiration}")
    private Long refreshExpiration;

    private SecretKey key;

    @PostConstruct
    public void init() {
        this.key = Keys.hmacShaKeyFor(secret.getBytes());
    }

    public String generateToken(String username, Long userId, List<String> roles, String userType) {
        Map<String, Object> claims = new HashMap<>();
        // 确保userId在token中以String类型存储，避免类型转换问题
        claims.put("userId", userId.toString());
        claims.put("roles", roles);
        claims.put("userType", userType);
        claims.put("role", roles != null && !roles.isEmpty() ? roles.get(0) : "USER");
        return createToken(claims, username, expiration);
    }

    public String generateRefreshToken(String username, Long userId) {
        Map<String, Object> claims = new HashMap<>();
        // 确保userId在token中以String类型存储，避免类型转换问题
        claims.put("userId", userId.toString());
        claims.put("refresh", true);
        return createToken(claims, username, refreshExpiration);
    }

    private String createToken(Map<String, Object> claims, String subject, Long expirationTime) {
        Date now = new Date();
        Date validity = new Date(now.getTime() + expirationTime);

        return Jwts.builder()
                .claims(claims)
                .subject(subject)
                .issuedAt(now)
                .expiration(validity)
                .signWith(key)
                .compact();
    }

    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    public String extractUserId(String token) {
        Object userIdObj = extractClaim(token, claims -> claims.get("userId"));
        if (userIdObj == null) {
            return null;
        }
        // 统一将userId转换为String类型
        if (userIdObj instanceof Long) {
            return userIdObj.toString();
        } else if (userIdObj instanceof Integer) {
            return ((Integer) userIdObj).toString();
        } else if (userIdObj instanceof String) {
            String userIdStr = (String) userIdObj;
            return userIdStr != null ? userIdStr.trim() : null;
        }
        return null;
    }

    public String extractRole(String token) {
        return extractClaim(token, claims -> claims.get("role", String.class));
    }

    public Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }

    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    private Claims extractAllClaims(String token) {
        return Jwts.parser().verifyWith(key).build().parseSignedClaims(token).getPayload();
    }

    private Boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }

    public Boolean isInvalid(String token) {
        try {
            extractAllClaims(token);
            return isTokenExpired(token);
        } catch (Exception e) {
            System.out.println("Token validation error: " + e.getMessage());
            return true;
        }
    }

    // 保持向后兼容的方法
    public Claims getAllClaimsFromToken(String token) {
        return extractAllClaims(token);
    }

    public String getUsername(String token) {
        return extractUsername(token);
    }

    public Long getUserId(String token) {
        String userIdStr = extractUserId(token);
        if (userIdStr != null && !userIdStr.trim().isEmpty()) {
            try {
                return Long.parseLong(userIdStr.trim());
            } catch (NumberFormatException e) {
                System.out.println("解析用户ID失败: " + e.getMessage());
                return null;
            }
        }
        return null;
    }

    public List<String> getRoles(String token) {
        return getAllClaimsFromToken(token).get("roles", List.class);
    }

    public String getUserType(String token) {
        return getAllClaimsFromToken(token).get("userType", String.class);
    }

    public boolean isRefreshToken(String token) {
        return Boolean.TRUE.equals(getAllClaimsFromToken(token).get("refresh", Boolean.class));
    }
}